/**
 * Copyright 2010 Steve Garon Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language governing permissions and limitations under the
 * License.
 */
package org.jared.synodroid.common.protocol.v31;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jared.synodroid.Synodroid;
import org.jared.synodroid.common.SynoServer;
import org.jared.synodroid.common.data.SharedDirectory;
import org.jared.synodroid.common.data.Task;
import org.jared.synodroid.common.data.TaskContainer;
import org.jared.synodroid.common.data.TaskDetail;
import org.jared.synodroid.common.data.TaskFile;
import org.jared.synodroid.common.data.TaskProperties;
import org.jared.synodroid.common.data.TaskStatus;
import org.jared.synodroid.common.protocol.DSHandler;
import org.jared.synodroid.common.protocol.DSMException;
import org.jared.synodroid.common.protocol.MultipartBuilder;
import org.jared.synodroid.common.protocol.Part;
import org.jared.synodroid.common.protocol.QueryBuilder;
import org.jared.synodroid.common.protocol.StreamFactory;
import org.jared.synodroid.ds.Utils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.net.Uri;
import android.util.Log;

/**
 * @author Stave Garon (steve.garon at gmail dot com)
 */
class DSHandlerDSM31 implements DSHandler {

	// DownloadManager constant declaration
	private static final String DM_URI = "/download/downloadman.cgi";
	private static final String DM_URI_NEW = "/webman/modules/DownloadStation/dlm/downloadman.cgi";
	private static final String TORRENT_INFO = "/webman/modules/DownloadStation/dlm/torrent_info.cgi";

	/* The Synology's server */
	private SynoServer server;
	private boolean DEBUG;

	/**
	 * The constructor
	 * 
	 * @param serverP
	 */
	public DSHandlerDSM31(SynoServer serverP, boolean debug) {
		server = serverP;
		DEBUG = debug;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.Protocol#getAllTask()
	 */
	public TaskContainer getAllTask(int startP, int limitP, String sortAttrP, boolean ascendingP) throws Exception {
		ArrayList<Task> result = new ArrayList<Task>();
		TaskContainer container = new TaskContainer(result);
		// If we are logged on
		if (server.isConnected()) {
			QueryBuilder getAllRequest = new QueryBuilder().add("action", "getall");
			getAllRequest.add("start", "" + startP);
			getAllRequest.add("limit", "" + limitP);
			getAllRequest.add("sort", sortAttrP.toLowerCase());
			String asc = (ascendingP ? "ASC" : "DESC");
			getAllRequest.add("dir", asc);
			// Execute
			JSONObject jso = null;
			synchronized (server) {
				jso = server.sendJSONRequest(DM_URI_NEW, getAllRequest.toString(), "GET");
			}
			boolean success = jso.getBoolean("success");
			// If request succeded
			if (success) {
				// Get the totals rates
				String totalUp = jso.getString("total_up");
				String totalDown = jso.getString("total_down");
				int totalTasks = jso.getInt("total");
				container.setTotalUp(totalUp);
				container.setTotalDown(totalDown);
				container.setTotalTasks(totalTasks);
				JSONArray items = jso.getJSONArray("items");
				for (int iLoop = 0; iLoop < items.length(); iLoop++) {
					JSONObject item = items.getJSONObject(iLoop);
					// Create the task item
					Task task = new Task();
					task.fileName = item.getString("filename").trim();
					task.taskId = item.getInt("task_id");
					task.downloadRate = item.getString("current_rate").trim();
					task.downloadSize = item.getString("current_size").trim();
					String prog = item.getString("progress").trim();
					int index = prog.indexOf("%");
					// If a value could be found ('%' found)
					if (index != -1) {
						prog = prog.substring(0, index);
						try {
							task.downloadProgress = (int) Float.parseFloat(prog);
						} catch (NumberFormatException ex) {
							// Set to unknown
							task.downloadProgress = -1;
						}
					}
					// Set to unknown
					else {
						task.downloadProgress = -1;
					}
					task.status = item.getString("status");
					task.eta = Utils.computeTimeLeft(item.getInt("timeleft"));
					task.totalSize = item.getString("total_size").trim();
					task.uploadRate = item.getString("upload_rate").trim();
					task.creator = item.getString("username").trim();
					if (task.creator.equals("")) {
						task.creator = server.getUser();
					}
					task.server = server;
					result.add(task);
				}
			}
			// Try to do something
			else {
				String reason = jso.getJSONObject("errno").getString("key");
				throw new DSMException(reason);
			}
		}
		return container;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.protocol.DSHandler#delete(org.jared.synodroid .common.data.Task)
	 */
	public void delete(Task taskP) throws Exception {
		// If we are logged on
		if (server.isConnected()) {
			try {
				QueryBuilder getAllRequest = new QueryBuilder().add("action", "delete").add("idList", "" + taskP.taskId);
				// Execute
				synchronized (server) {
					server.sendJSONRequest(DM_URI_NEW, getAllRequest.toString(), "GET");
				}
			} catch (Exception e) {
				if (DEBUG) Log.e(Synodroid.DS_TAG, "Not expected exception occured while deleting id:" + taskP.taskId, e);
				throw e;
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.protocol.DSHandler#clearAll()
	 */
	public void clearAll() throws Exception {
		// If we are logged on
		if (server.isConnected()) {
			try {
				QueryBuilder getAllRequest = new QueryBuilder().add("action", "clear").add("idList", "");
				// Execute
				synchronized (server) {
					server.sendJSONRequest(DM_URI_NEW, getAllRequest.toString(), "GET");
				}
			} catch (Exception e) {
				if (DEBUG) Log.e(Synodroid.DS_TAG, "Not expected exception occured while clearing tasks", e);
				throw e;
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.protocol.DSHandler#resume(org.jared.synodroid .common.data.Task)
	 */
	public void resume(Task taskP) throws Exception {
		// If we are logged on
		if (server.isConnected()) {
			QueryBuilder getAllRequest = new QueryBuilder().add("action", "resume").add("idList", "" + taskP.taskId);
			// Execute
			synchronized (server) {
				server.sendJSONRequest(DM_URI_NEW, getAllRequest.toString(), "GET");
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.protocol.DSHandler#resumeAll(List<org.jared. synodroid. common.data.Task>)
	 */
	public void resumeAll(List<Task> taskP) throws Exception {
		for (Task task : taskP) {
			if (task.status.equals(TaskStatus.TASK_PAUSED.toString())) {
				resume(task);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.protocol.DSHandler#stop(org.jared.synodroid. common.data.Task)
	 */
	public void stop(Task taskP) throws Exception {
		// If we are logged on
		if (server.isConnected()) {
			QueryBuilder getAllRequest = new QueryBuilder().add("action", "stop").add("idList", "" + taskP.taskId);
			// Execute
			synchronized (server) {
				server.sendJSONRequest(DM_URI_NEW, getAllRequest.toString(), "GET");
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.protocol.DSHandler#stopAll(List<org.jared.synodroid . common.data.Task>)
	 */
	public void stopAll(List<Task> taskP) throws Exception {
		for (Task task : taskP) {
			if (task.status.equals(TaskStatus.TASK_DOWNLOADING.toString()) || task.status.equals(TaskStatus.TASK_PRE_SEEDING.toString()) || task.status.equals(TaskStatus.TASK_SEEDING.toString()) || task.status.equals(TaskStatus.TASK_HASH_CHECKING.toString()) || task.status.equals(TaskStatus.TASK_WAITING.toString())) {
				stop(task);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.protocol.DSHandler#getFiles(org.jared.synodroid .common.data.Task)
	 */
	public List<TaskFile> getFiles(Task taskP) throws Exception {
		ArrayList<TaskFile> result = new ArrayList<TaskFile>();
		// If we are logged on
		if (server.isConnected()) {
			QueryBuilder getAllRequest = new QueryBuilder().add("action", "list_file").add("task_id", "" + taskP.taskId);
			// Execute
			JSONObject json = null;
			synchronized (server) {
				json = server.sendJSONRequest(TORRENT_INFO, getAllRequest.toString(), "GET");
			}
			boolean success = json.getBoolean("success");
			// If request succeded
			if (success) {
				JSONArray array = json.getJSONArray("items");
				for (int iLoop = 0; iLoop < array.length(); iLoop++) {
					JSONObject obj = array.getJSONObject(iLoop);
					// Create the file
					TaskFile file = new TaskFile();
					file.name = obj.getString("name");
					file.filesize = obj.getString("size");
					file.download = obj.getBoolean("wanted");
					file.id = obj.getInt("index");
					result.add(file);
				}
				array.length();
			}
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.protocol.DSHandler#getDetails(org.jared.synodroid .common.data.Task)
	 */
	public TaskDetail getDetails(Task taskP) throws Exception {
		TaskDetail result = new TaskDetail();
		// If we are logged on
		if (server.isConnected()) {
			QueryBuilder getAllRequest = new QueryBuilder().add("action", "getone").add("taskid", "" + taskP.taskId).add("update", "1");
			// Execute
			JSONObject json = null;
			synchronized (server) {
				json = server.sendJSONRequest(DM_URI_NEW, getAllRequest.toString(), "GET");
			}
			boolean success = json.getBoolean("success");
			// If successful then build details list
			if (success) {
				JSONObject data = json.getJSONObject("data");
				if (data.has("stime"))
					result.seedingDate = data.getString("stime");
				if (data.has("totalpeer"))
					result.peersTotal = Utils.toLong(data.getString("totalpeer"));
				if (data.has("currpeer"))
					result.peersCurrent = Utils.toLong(data.getString("currpeer"));
				if (data.has("istorrent"))
					result.isTorrent = data.getBoolean("istorrent");
				if (data.has("speed")) {
					Pattern p = Pattern.compile("(((\\d)*\\.(\\d)*) KB/s)");
					Matcher m = p.matcher(data.getString("speed"));
					if (m.find() && m.groupCount() >= 2) {
						result.speedUpload = Utils.toDouble(m.group(2));
					}
					if (m.find() && m.groupCount() >= 2) {
						result.speedDownload = Utils.toDouble(m.group(2));
					} else {
						result.speedDownload = result.speedUpload;
					}
				}
				if (data.has("filename"))
					result.fileName = data.getString("filename");
				if (data.has("username"))
					result.userName = data.getString("username");
				if (data.has("totalpieces"))
					result.piecesTotal = Utils.toLong(data.getString("totalpieces"));
				if (data.has("transfered")) {
					Pattern p = Pattern.compile("((\\d*\\.\\d*)\\s[KMGT]B)");
					Matcher m = p.matcher(data.getString("transfered"));
					if (m.find() && m.groupCount() >= 1) {
						result.bytesUploaded = Utils.fileSizeToBytes(m.group(1));
					}
					// If you could find another matching group, it means downmload
					// informations are present
					if (m.find() && m.groupCount() >= 1) {
						result.bytesDownloaded = Utils.fileSizeToBytes(m.group(1));
					}
					// Otherwise download informations were the first matching (no upload
					// information)
					else {
						result.bytesDownloaded = result.bytesUploaded;
						result.bytesUploaded = 0;
					}
					result.bytesRatio = 0;
					if (result.bytesDownloaded != 0) {
						result.bytesRatio = (int) (((float) result.bytesUploaded / (float) result.bytesDownloaded) * 100);
					}
				}
				if (data.has("seedelapsed"))
					result.seedingElapsed = data.getInt("seedelapsed");
				if (data.has("isnzb"))
					result.isNZB = data.getBoolean("isnzb");
				if (data.has("destination"))
					result.destination = data.getString("destination");
				if (data.has(("url")))
					result.url = data.getString("url");
				if (data.has("ctime"))
					result.creationDate = data.getString("ctime");
				if (data.has("status"))
					result.status = data.getString("status");
				if (data.has("seeding_interval"))
					result.seedingInterval = data.getInt("seeding_interval");
				if (data.has("currpieces"))
					result.piecesCurrent = Utils.toLong(data.getString("currpieces"));
				if (data.has("id"))
					result.taskId = data.getInt("id");
				if (data.has("seeding_ratio"))
					result.seedingRatio = data.getInt("seeding_ratio");
				if (data.has("filesize"))
					result.fileSize = Utils.fileSizeToBytes(data.getString("filesize"));
				if (data.has("seeders_leechers")) {
					Pattern p = Pattern.compile("(\\d+)(/)(\\d+)");
					String v = data.getString("seeders_leechers");
					Matcher m = p.matcher(v);
					if (m.find()) {
						if (m.groupCount() >= 1)
							result.seeders = Utils.toLong(m.group(1));
						if (m.groupCount() >= 3)
							result.leechers = Utils.toLong(m.group(3));
					}
				}
			}
			// Otherwise throw a exception
			else {
				String reason = "";
				if (json.has("reason")) {
					reason = json.getString("reason");
				} else if (json.has("errno")) {
					JSONObject err = json.getJSONObject("errno");
					reason = err.getString("key");
				}
				throw new DSMException(reason);
			}
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.protocol.DSHandler#upload(android.net.Uri)
	 */
	public void upload(Uri uriP) throws Exception {
		// If we are logged on
		if (server.isConnected()) {
			if (uriP.getPath() != null) {
				// Create the multipart
				MultipartBuilder builder = new MultipartBuilder("-----------7dabb2d41348", DEBUG);

				// The field's part
				builder.addPart(new Part("field").setContent("task_id".getBytes()));
				// The direction's part
				builder.addPart(new Part("direction").setContent("ASC".getBytes()));
				// The url_http's part
				builder.addPart(new Part("url_http").setContent("".getBytes()));
				// The url_https's part
				builder.addPart(new Part("url_https").setContent("".getBytes()));
				// The url_ftp's part
				builder.addPart(new Part("url_ftp").setContent("".getBytes()));

				// The upload_type's part
				builder.addPart(new Part("upload_type").setContent("torrent".getBytes()));
				// The torrent's part
				Part filePart = new Part("torrent").addExtra("filename", uriP.getPath());
				filePart.setContentType("application/octet-stream");

				// Get the stream according to the Uri
				byte[] buffer = StreamFactory.getStream(uriP);

				// Set the content
				filePart.setContent(buffer);
				builder.addPart(filePart);
				// Execute
				synchronized (server) {
					server.sendMultiPart(DM_URI, builder);
				}
			}
		}
	}

	public void uploadUrl(Uri uriP) throws Exception {
		// If we are logged on
		if (server.isConnected()) {
			if (uriP.toString() != null) {
				// Create the multipart
				MultipartBuilder builder = new MultipartBuilder("-----------7dabb2d41348", DEBUG);

				// The field's part
				builder.addPart(new Part("field").setContent("task_id".getBytes()));
				// The direction's part
				builder.addPart(new Part("direction").setContent("ASC".getBytes()));

				if (uriP.toString().toLowerCase().startsWith("https:")) {
					// The url_http's part
					builder.addPart(new Part("url_http").setContent("".getBytes()));
					// The url_https's part
					builder.addPart(new Part("url_https").setContent(uriP.toString().getBytes()));
					// The url_ftp's part
					builder.addPart(new Part("url_ftp").setContent("".getBytes()));
				} else if (uriP.toString().toLowerCase().startsWith("http:")) {
					// The url_http's part
					builder.addPart(new Part("url_http").setContent(uriP.toString().getBytes()));
					// The url_https's part
					builder.addPart(new Part("url_https").setContent("".getBytes()));
					// The url_ftp's part
					builder.addPart(new Part("url_ftp").setContent("".getBytes()));
				} else if (uriP.toString().toLowerCase().startsWith("ftp:")) {
					// The url_http's part
					builder.addPart(new Part("url_http").setContent("".getBytes()));
					// The url_https's part
					builder.addPart(new Part("url_https").setContent("".getBytes()));
					// The url_ftp's part
					builder.addPart(new Part("url_ftp").setContent(uriP.toString().getBytes()));
				} else {
					return;
				}
				// The url_ftp's part
				builder.addPart(new Part("url").setContent(uriP.toString().getBytes()));
				// The upload_type's part
				builder.addPart(new Part("upload_type").setContent("url".getBytes()));

				// Execute
				synchronized (server) {
					server.sendMultiPart(DM_URI, builder);
				}
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.protocol.DSHandler#getTaskProperty(org.jared.synodroid .common.data.Task)
	 */
	public TaskProperties getTaskProperty(Task taskP) throws Exception {
		// torrent_info.cgi?_dc=1299264441500&action=get_property&task_id=2001
		QueryBuilder getPropReq = new QueryBuilder().add("action", "get_property").add("task_id", "" + taskP.taskId);

		TaskProperties output = new TaskProperties();
		output.id = "" + taskP.taskId;

		JSONObject json = null;
		synchronized (server) {
			json = server.sendJSONRequest(TORRENT_INFO, getPropReq.toString(), "POST");
		}
		boolean success = json.getBoolean("success");
		// If not successful then throw an exception
		if (!success) {
			String reason = "";
			if (json.has("reason")) {
				reason = json.getString("reason");
			} else if (json.has("errno")) {
				JSONObject err = json.getJSONObject("errno");
				reason = err.getString("key");
			}
			throw new DSMException(reason);
		} else {
			try {
				if (json.has("ul_rate")) {
					output.ul_rate = json.getInt("ul_rate");
				}
				if (json.has("dl_rate")) {
					output.dl_rate = json.getInt("dl_rate");
				}
				if (json.has("max_peers")) {
					output.max_peers = json.getInt("max_peers");
				}
				if (json.has("priority")) {
					output.priority = json.getInt("priority");
				}
				if (json.has("seeding_ratio")) {
					output.seeding_ratio = json.getInt("seeding_ratio");
				}
				if (json.has("seeding_interval")) {
					output.seeding_interval = json.getInt("seeding_interval");
				}
				if (json.has("destination")) {
					output.destination = json.getString("destination");
				}

			} catch (JSONException e) {
			}

		}
		return output;
	}

	public void setTaskProperty(final Task taskP, int ul_rate, int dl_rate, int priority, int max_peers, String destination, int seeding_ratio, int seeding_interval) throws Exception {
		// action=set_property
		// &task_ids=[2001]
		// &settings={"ext-comp-1434":"","ul_rate":5,"dl_rate":5,"priority":-1,"max_peers":100,"destination":"upload","seeding_ratio":25,"seeding_interval":90}'

		// Create the JSON request
		QueryBuilder updateTaskRequest = new QueryBuilder().add("action", "set_property").add("task_ids", "[" + taskP.taskId + "]");
		JSONObject data = new JSONObject();

		data.put("ext-comp-1434", "");
		data.put("ul_rate", ul_rate);
		data.put("dl_rate", dl_rate);
		data.put("priority", priority);
		data.put("max_peers", max_peers);
		data.put("destination", destination);
		data.put("seeding_ratio", seeding_ratio);
		data.put("seeding_interval", seeding_interval);

		updateTaskRequest.add("settings", data.toString());

		// Execute it to the server
		JSONObject json = null;
		synchronized (server) {
			json = server.sendJSONRequest(TORRENT_INFO, updateTaskRequest.toString(), "POST");
		}
		boolean success = json.getBoolean("success");
		// If not successful then throw an exception
		if (!success) {
			String reason = "";
			if (json.has("reason")) {
				reason = json.getString("reason");
			} else if (json.has("errno")) {
				JSONObject err = json.getJSONObject("errno");
				reason = err.getString("key");
			}
			throw new DSMException(reason);
		}

	}

	public void setFilePriority(final Task taskP, List<TaskFile> filesP) throws Exception {
		// action=set_files_priority&task_id=2001&priority=skip&indexes=%5B1%5D
		List<Integer> l_skip = new ArrayList<Integer>();
		List<Integer> l_normal = new ArrayList<Integer>();

		for (TaskFile taskFile : filesP) {
			if (taskFile.download) {
				l_normal.add(taskFile.id);
			} else {
				l_skip.add(taskFile.id);
			}
		}

		if (l_skip.size() != 0) {
			QueryBuilder updateSkipped = new QueryBuilder().add("action", "set_files_priority").add("task_id", "" + taskP.taskId).add("priority", "skip").add("indexes", l_skip.toString());

			// Execute it to the server
			JSONObject json = null;
			synchronized (server) {
				json = server.sendJSONRequest(TORRENT_INFO, updateSkipped.toString(), "POST");
			}
			boolean success = json.getBoolean("success");
			// If not successful then throw an exception
			if (!success) {
				String reason = "";
				if (json.has("reason")) {
					reason = json.getString("reason");
				} else if (json.has("errno")) {
					JSONObject err = json.getJSONObject("errno");
					reason = err.getString("key");
				}
				throw new DSMException(reason);
			}
		}

		if (l_normal.size() != 0) {
			QueryBuilder updateNormal = new QueryBuilder().add("action", "set_files_priority").add("task_id", "" + taskP.taskId).add("priority", "1").add("indexes", l_normal.toString());

			// Execute it to the server
			JSONObject json = null;
			synchronized (server) {
				json = server.sendJSONRequest(TORRENT_INFO, updateNormal.toString(), "POST");
			}
			boolean success = json.getBoolean("success");
			// If not successful then throw an exception
			if (!success) {
				String reason = "";
				if (json.has("reason")) {
					reason = json.getString("reason");
				} else if (json.has("errno")) {
					JSONObject err = json.getJSONObject("errno");
					reason = err.getString("key");
				}
				throw new DSMException(reason);
			}
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.protocol.DSHandler#updateTask(org.jared.synodroid .common.data.Task, java.util.List, int, int)
	 */
	public void updateTask(Task taskP, List<TaskFile> filesP, int seedingRatioP, int seedingIntervalP) throws Exception {
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.protocol.DSHandler#enumSharedDirectory()
	 */
	public List<SharedDirectory> enumSharedDirectory() throws Exception {
		List<SharedDirectory> result = new ArrayList<SharedDirectory>();
		// Create the JSON request
		QueryBuilder updateTaskRequest = new QueryBuilder().add("action", "enumshares");
		// Execute it to the server
		JSONObject json = null;
		synchronized (server) {
			json = server.sendJSONRequest(DM_URI_NEW, updateTaskRequest.toString(), "GET");
		}
		boolean success = json.getBoolean("success");
		// If request succeded
		if (success) {
			JSONArray array = json.getJSONArray("items");
			for (int iLoop = 0; iLoop < array.length(); iLoop++) {
				JSONObject obj = array.getJSONObject(iLoop);
				// Create the file
				SharedDirectory dir = new SharedDirectory(obj.getString("name"));
				dir.description = obj.getString("description");
				result.add(dir);
			}
		}
		// If not successful then throw an exception
		else {
			String reason = "";
			if (json.has("reason")) {
				reason = json.getString("reason");
			} else if (json.has("errno")) {
				JSONObject err = json.getJSONObject("errno");
				reason = err.getString("key");
			}
			throw new DSMException(reason);
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.protocol.DSHandler#setSharedDirectory(java.lang .String)
	 */
	public void setSharedDirectory(Task taskP, String directoryP) throws Exception {
		// If we are logged on
		if (server.isConnected()) {
			QueryBuilder setShared = new QueryBuilder().add("action", "shareset").add("share", directoryP);
			if (taskP != null) {
				setShared.add("taskid", "" + taskP.taskId);
			}
			// Execute
			synchronized (server) {
				server.sendJSONRequest(DM_URI_NEW, setShared.toString(), "POST");
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.protocol.DSHandler#getSharedDirectory()
	 */
	public String getSharedDirectory() throws Exception {
		String result = null;
		// If we are logged on
		if (server.isConnected()) {
			QueryBuilder getShared = new QueryBuilder().add("action", "shareget");
			// Execute
			JSONObject json;
			synchronized (server) {
				json = server.sendJSONRequest(DM_URI_NEW, getShared.toString(), "GET");
			}
			boolean success = json.getBoolean("success");
			// If request succeded
			if (success) {
				result = json.getString("shareName");
			}
			// If not successful then throw an exception
			else {
				String reason = "";
				if (json.has("reason")) {
					reason = json.getString("reason");
				} else if (json.has("errno")) {
					JSONObject err = json.getJSONObject("errno");
					reason = err.getString("key");
					// Means that no shared directory has been set currently: don't throw an exception
					if (reason != null && reason.equals("download_error_user_removed")) {
						return "";
					}
				} else if (json.has("disable_err")) {
					reason = json.getString("disable_err");
					if (reason.equals("none") || reason.equals("sharenotfound")){
						return "";
					}
				}
				throw new DSMException(reason);
			}
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jared.synodroid.common.protocol.DSHandler#getOriginalLink(org.jared .synodroid.common.data.Task)
	 */
	public StringBuffer getOriginalFile(Task taskP) throws Exception {
		StringBuffer result = null;
		// If we are logged on
		if (server.isConnected()) {
			QueryBuilder getOriginal = new QueryBuilder().add("action", "torrent").add("id", "" + taskP.taskId).add("_rn", "" + System.currentTimeMillis());
			// Execute
			synchronized (server) {
				String uri = DM_URI_NEW + "/" + taskP.originalLink;
				result = server.download(uri, getOriginal.toString());
			}
		}
		return result;
	}

}
